import { bearing, destination, distance, featureOfArc, type LngLat } from '@/geom/great-circle'
import { overlay, type LineFeature, type SymbolFeature } from '@/map'
import { IgnoreMouseDrag, isRight, type InteractionTip } from '@/map-interaction'
import { highLightProperties } from '@/map/highlights'
import { meter2MetricStr } from '@/widgets'
import type { Map, MapMouseEvent } from 'mapbox-gl'
import { addAuxArc } from './core'

function formatAngle(a: number) {
  return `${Math.floor(a * 100.0) / 100.0}°`
}

export class DrawAuxArc extends IgnoreMouseDrag {
  public readonly type: string = 'DrawAuxArc'
  private center: LngLat | null = null
  private centerCoord: number[] = []
  private bearing1: number | null = null
  private lineProperties = highLightProperties.line.primary
  private lineProperties2rd = highLightProperties.line.secondary
  private symbolProperties = highLightProperties.symbol.secondary
  private clockwise: boolean
  public readonly tip: InteractionTip

  constructor(clockwise: boolean) {
    super()
    this.clockwise = clockwise
    const title = clockwise ? '绘制辅助圆弧' : '绘制辅助圆弧[逆时针]'
    this.tip = {
      title,
      content:
        '1. 左键点击确定圆心.\n2. 点击确定起始方位.\n3. 点击确定结束方位和半径.\n4. 右键取消绘制.'
    }
  }

  public attach(map: Map): void {
    super.attach(map)
    map.getCanvas().style.cursor = 'crosshair'
    console.log(this.lineProperties)
  }

  public detach(map: Map): void {
    map.getCanvas().style.cursor = 'auto'
    super.detach(map)
  }

  public onMouseMove(evt: MapMouseEvent): void {
    const { center, centerCoord, bearing1 } = this
    if (!center) {
      return
    }
    const { lng, lat } = evt.lngLat
    const pt = { lng, lat }
    const ptCoord = [lng, lat]
    if (bearing1 === null) {
      const b1 = bearing(center, pt)
      overlay.updateSymbol({
        type: 'Feature',
        geometry: {
          type: 'Point',
          coordinates: ptCoord
        },
        properties: this.symbolProperties(formatAngle(b1))
      })
      overlay.updateLine({
        type: 'Feature',
        geometry: {
          type: 'LineString',
          coordinates: [centerCoord, ptCoord]
        },
        properties: this.lineProperties2rd
      })
      return
    }

    const b1 = bearing1
    const radius = distance(center, pt)
    const b2 = bearing(center, pt)
    const pt1 = destination(center, b1, radius)
    const pt1Coord = [pt1.lng, pt1.lat]
    const sf1: SymbolFeature = {
      type: 'Feature',
      geometry: {
        type: 'Point',
        coordinates: pt1Coord
      },
      properties: this.symbolProperties(formatAngle(b1))
    }
    const sf2: SymbolFeature = {
      type: 'Feature',
      geometry: {
        type: 'Point',
        coordinates: ptCoord
      },
      properties: this.symbolProperties(formatAngle(b1) + '/' + meter2MetricStr(radius))
    }
    const l1: LineFeature = {
      type: 'Feature',
      geometry: {
        type: 'LineString',
        coordinates: [centerCoord, pt1Coord]
      },
      properties: this.lineProperties2rd
    }
    const l2: LineFeature = {
      type: 'Feature',
      geometry: {
        type: 'LineString',
        coordinates: [centerCoord, ptCoord]
      },
      properties: this.lineProperties2rd
    }
    let arc: LineFeature
    if (this.clockwise) {
      arc = featureOfArc(center, radius, b1, b2, this.lineProperties)
    } else {
      arc = featureOfArc(center, radius, b2, b1, this.lineProperties)
    }
    overlay.updateSymbols([sf1, sf2])
    overlay.updateLines([l1, l2, arc])
  }

  public onMouseClick(evt: MapMouseEvent): void {
    if (isRight(evt)) {
      this.finish()
      return
    }
    const { center, bearing1, clockwise } = this
    const { lng, lat } = evt.lngLat
    const pt = { lng, lat }
    const ptCoord = [lng, lat]
    if (!center) {
      this.center = pt
      this.centerCoord = ptCoord
      return
    }
    if (bearing1 === null) {
      const b1 = bearing(center, pt)
      this.bearing1 = b1
      return
    }
    const b1 = bearing1
    const radius = distance(center, pt)
    const b2 = bearing(center, pt)
    if (clockwise) {
      addAuxArc(center, radius, b1, b2)
    } else {
      addAuxArc(center, radius, b2, b1)
    }
    this.finish()
    return
  }
}
